package co.fitstart.admin.service.impl;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.demo2do.core.persistence.GenericDaoSupport;
import com.demo2do.core.persistence.annotation.Dynamic;
import com.demo2do.core.support.Page;

import co.fitstart.admin.dao.GroupTemplateDao;
import co.fitstart.admin.service.GroupTemplateService;
import co.fitstart.entity.courseware.dietary.DietaryProgramTemplate;
import co.fitstart.entity.courseware.dietary.DietaryProgramType;
import co.fitstart.entity.courseware.fitnessgroup.BatchCoursewareTemplate;
import co.fitstart.entity.courseware.fitnessgroup.BatchCoursewareType;
import co.fitstart.entity.courseware.fitnessgroup.CoursewareMovementType;
import co.fitstart.entity.courseware.fitnessgroup.CoursewareTemplate;
import co.fitstart.entity.courseware.fitnessgroup.DailyCoursewareTemplate;
import co.fitstart.entity.courseware.fitnessgroup.DailyCoursewareType;
import co.fitstart.entity.courseware.fitnessgroup.FitnessGroup;
import co.fitstart.entity.courseware.fitnessgroup.FitnessGroupType;
import co.fitstart.entity.courseware.fitnessgroup.SpecialCoursewareTemplate;

@Service("fitnessGroupService")
public class GroupTemplateServiceImpl implements GroupTemplateService{
    
    @Dynamic
    private GroupTemplateDao groupTemplateDao;
    
    @Autowired
    private GenericDaoSupport genericDaoSupport;
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#listFitnessGroup(boolean, com.demo2do.core.support.Page)
     */
    public List<FitnessGroup> listFitnessGroup(FitnessGroupType type, Page page) {
        List<FitnessGroup> result = groupTemplateDao.listFitnessGroup(new FitnessGroupType[]{type}, page.getBeginIndex(), page.getMaxResultRecords());

        page.calculate(result.size());
        return result.size() > page.getEveryPage() ? result.subList(0, page.getEveryPage()) : result;
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#loadFitnessGroup(java.lang.Long)
     */
    public FitnessGroup loadFitnessGroup(Long fitnessGroupId) {
        return genericDaoSupport.load(FitnessGroup.class, fitnessGroupId);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.FitnessGroupService#create(co.fitstart.entity.courseware.fitnessgroup.FitnessGroup)
     */
    public void createFitnessGroup(FitnessGroup fitnessGroup) {
        // create fitnessGroup first
        genericDaoSupport.save(fitnessGroup.initilization());
        
        // if type is special create specialCoursewareTemplate
        if(fitnessGroup.getType().isSpecialty()) {
            this.createSpecialCourseware(fitnessGroup);
        } else { // create weekly batchCoursewareTemplate and dailyCoursewareTemplate
            this.createWeeklyCourseware(fitnessGroup);
        }
        
        // if courseType is offline create course batchCoursewareTemplate
        if(fitnessGroup.getType().isOffline()) {
            this.createCourseCourseware(fitnessGroup);
        }
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#copyFitnessGroup(java.lang.String, co.fitstart.entity.courseware.fitnessgroup.FitnessGroup)
     */
    public void copyFitnessGroup(String name, FitnessGroup fitnessGroup) {
        FitnessGroup newFitnessGroup = new FitnessGroup(fitnessGroup, name);
        genericDaoSupport.save(newFitnessGroup);
        
        // if type is special copy specialCoursewareTemplate
        if(fitnessGroup.getType().isSpecialty()) {
            this.copySpecialCourseware(newFitnessGroup, fitnessGroup);
        } else { // copy weekly batchCoursewareTemplate and dailyCoursewareTemplate
            this.copyOnlineAndOfflineCourseware(newFitnessGroup, fitnessGroup);
        }
    }
    
    /**
     * 
     * @param fitnessGroup
     */
    private void createSpecialCourseware(FitnessGroup fitnessGroup) {
        SpecialCoursewareTemplate specialCoursewareTemplate = new SpecialCoursewareTemplate("第一节", fitnessGroup);
        genericDaoSupport.save(specialCoursewareTemplate);
    }
    
    /**
     * 
     * @param newFitnessGroup
     * @param fitnessGroup
     */
    private void copySpecialCourseware(FitnessGroup newFitnessGroup, FitnessGroup fitnessGroup) {
        SpecialCoursewareTemplate newSpecial = new SpecialCoursewareTemplate("第一节", newFitnessGroup);
        genericDaoSupport.save(newSpecial);
        
        SpecialCoursewareTemplate special = groupTemplateDao.loadSpecialCoursewareTemplate(fitnessGroup);
        
        List<CoursewareTemplate> coursewares = groupTemplateDao.listCoursewareTemplate(special);
        
        for(CoursewareTemplate courseware : coursewares) {
            CoursewareTemplate newCourseware = new CoursewareTemplate(courseware, newSpecial);
            genericDaoSupport.save(newCourseware);
        }
    }
    
    /**
     * 
     * @param fitnessGroup
     */
    private void createWeeklyCourseware(FitnessGroup fitnessGroup) {
        // if type is online create warm-up period
        if(fitnessGroup.getType().isOnline()) {
            BatchCoursewareTemplate template = this.createBatchCoursewareTemplate("预热期", 0, BatchCoursewareType.WEEKLY, fitnessGroup);
            // create dailyCoursewareTemplate
            for(int j=1; j<4; j++) {
                this.createDailyCoursewareTemplate("Day " + j, j, template);
            }
        }
        
        // create other weekly courseware
        for(int i=1; i<=fitnessGroup.getWeeks(); i++) {
            BatchCoursewareTemplate weeklyTemplate = this.createBatchCoursewareTemplate("第" + i + "周", i, BatchCoursewareType.WEEKLY, fitnessGroup);
            
            // create dailyCoursewareTemplate
            for(int j=1; j<8; j++) {
                this.createDailyCoursewareTemplate("Day " + j, j, weeklyTemplate);
            }
        }
    }
    
    /**
     * 
     * @param newFitnessGroup
     * @param fitnessGroup
     */
    private void copyOnlineAndOfflineCourseware(FitnessGroup newFitnessGroup, FitnessGroup fitnessGroup) {
        List<BatchCoursewareTemplate> batchs = groupTemplateDao.listBatchCoursewareTemplate(fitnessGroup);
        
        for(BatchCoursewareTemplate batch : batchs) {
            BatchCoursewareTemplate newBatch = new BatchCoursewareTemplate(batch, newFitnessGroup);
            genericDaoSupport.save(newBatch);
            
            List<DailyCoursewareTemplate> dailys = groupTemplateDao.listDailyCoursewareTemplate(batch);
            
            for(DailyCoursewareTemplate daily : dailys) {
                DailyCoursewareTemplate newDaily = new DailyCoursewareTemplate(daily, newBatch);
                genericDaoSupport.save(newDaily);
                
                List<CoursewareTemplate> coursewares = groupTemplateDao.listCoursewareTemplate(daily);
                
                for(CoursewareTemplate courseware : coursewares) {
                    CoursewareTemplate newCourseware = new CoursewareTemplate(courseware, newDaily);
                    genericDaoSupport.save(newCourseware);
                }
            }
        }
    }
    
    /**
     * 
     * @param fitnessGroup
     */
    private void createCourseCourseware(FitnessGroup fitnessGroup) {
        BatchCoursewareTemplate coursewareTemplate = this.createBatchCoursewareTemplate("上课课件", 1, BatchCoursewareType.COURSE, fitnessGroup);
        
        int hours = fitnessGroup.getHours();
        for(int i=1; i<=hours; i++) {
          this.createDailyCoursewareTemplate("session " + i, i, coursewareTemplate);
        }
    }
    
    /**
     * 
     * @param name
     * @param sorting
     * @param type
     * @param fitnessGroup
     * @return
     */
    private BatchCoursewareTemplate createBatchCoursewareTemplate(String name, int sorting, BatchCoursewareType type, FitnessGroup fitnessGroup) {
        BatchCoursewareTemplate batch = new BatchCoursewareTemplate(name, sorting, type, fitnessGroup);
        genericDaoSupport.save(batch);
        return batch;
    }
    
    /**
     * 
     * @param name
     * @param sorting
     * @param batch
     */
    private void createDailyCoursewareTemplate(String name, int sorting, BatchCoursewareTemplate batch) {
        DailyCoursewareTemplate courseDailyTemplate = new DailyCoursewareTemplate(name, sorting, batch);
        genericDaoSupport.save(courseDailyTemplate);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.FitnessGroupService#edit(co.fitstart.entity.courseware.fitnessgroup.FitnessGroup)
     */
    public void editFitnessGroup(FitnessGroup fitnessGroup) {
        genericDaoSupport.update(fitnessGroup.edit());
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.FitnessGroupService#delete(co.fitstart.entity.courseware.fitnessgroup.FitnessGroup)
     */
    public void deleteFitnessGroup(FitnessGroup fitnessGroup) {
        // delete fitnessGroup
        genericDaoSupport.update(fitnessGroup.disable());
        
        // if special courseware delete specialCoursewareTemplate
        if(fitnessGroup.getType().isSpecialty()) {
            this.deleteSpecialCourseware(fitnessGroup);
        } else {
            this.deleteCourseware(fitnessGroup);
        }
        
    }
    
    /**
     * 
     * @param fitnessGroup
     */
    private void deleteSpecialCourseware(FitnessGroup fitnessGroup) {
        // get and delete fitnessGroup's specialCoursewareTemplate
        List<SpecialCoursewareTemplate> specialCoursewareTemplates = groupTemplateDao.listSpecialCoursewareTemplate(fitnessGroup);
        for(SpecialCoursewareTemplate specialCoursewareTemplate : specialCoursewareTemplates) {
            genericDaoSupport.update(specialCoursewareTemplate.disable());
        }
        
        // delete coursewareTemplate
        groupTemplateDao.deleteSpecialCourseware(specialCoursewareTemplates);
    }
    
    /**
     * 
     * @param fitnessGroup
     */
    private void deleteCourseware(FitnessGroup fitnessGroup) {
        // delete batchCoursewareTemplate
        List<BatchCoursewareTemplate> batchCoursewareTemplates = groupTemplateDao.listBatchCoursewareTemplate(fitnessGroup);
        for(BatchCoursewareTemplate batchCoursewareTemplate : batchCoursewareTemplates) {
            genericDaoSupport.update(batchCoursewareTemplate.disable());
        }
        
        // delete dailyCoursewareTemplate
        List<DailyCoursewareTemplate> dailyCoursewareTemplates = groupTemplateDao.listDailyCoursewareTemplate(batchCoursewareTemplates);
        for(DailyCoursewareTemplate dailyCoursewareTemplate : dailyCoursewareTemplates) {
            genericDaoSupport.update(dailyCoursewareTemplate.disable());
        }
        
        // delete coursewareTemplate
        groupTemplateDao.deleteCourseware(dailyCoursewareTemplates);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#loadDailyCoursewareTemplate(java.lang.Long)
     */
    public DailyCoursewareTemplate loadDailyCoursewareTemplate(Long dailyCoursewareTemplateId) {
        return genericDaoSupport.load(DailyCoursewareTemplate.class, dailyCoursewareTemplateId);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#loadDailyCoursewareTemplate(co.fitstart.entity.courseware.fitnessgroup.BatchCoursewareTemplate, int)
     */
    public DailyCoursewareTemplate loadDailyCoursewareTemplate(BatchCoursewareTemplate batch, int sorting) {
        return groupTemplateDao.loadDailyCoursewareTemplate(batch, sorting);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#rest(co.fitstart.entity.courseware.fitnessgroup.DailyCoursewareTemplate)
     */
    public void rest(DailyCoursewareTemplate dailyCoursewareTemplate) {
        // if this dailyCoursewareTemplate have coursewareTemplates delete these coursewareTemplates
        groupTemplateDao.deleteCoursewareTemplate(dailyCoursewareTemplate);
        
        genericDaoSupport.update(dailyCoursewareTemplate.changeType(DailyCoursewareType.REST));
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#rest(co.fitstart.entity.courseware.fitnessgroup.SpecialCoursewareTemplate)
     */
    public void rest(SpecialCoursewareTemplate specialCoursewareTemplate) {
        // if this specialCoursewareTemplate have coursewareTemplates delete these coursewareTemplates
        groupTemplateDao.deleteCoursewareTemplate(specialCoursewareTemplate);
        
        genericDaoSupport.update(specialCoursewareTemplate.changeType(DailyCoursewareType.REST));
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#loadBatchCoursewareTemplate(java.lang.Long)
     */
    public BatchCoursewareTemplate loadBatchCoursewareTemplate(Long batchId) {
        return genericDaoSupport.load(BatchCoursewareTemplate.class, batchId);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#loadBatchCoursewareTemplate(co.fitstart.entity.courseware.fitnessgroup.FitnessGroup, int, co.fitstart.entity.courseware.fitnessgroup.BatchCoursewareType)
     */
    public BatchCoursewareTemplate loadBatchCoursewareTemplate(FitnessGroup fitnessGroup, int sorting, BatchCoursewareType type) {
        return groupTemplateDao.loadBatchCoursewareTemplate(fitnessGroup, type, sorting);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#editDiet(co.fitstart.entity.courseware.fitnessgroup.BatchCoursewareTemplate, co.fitstart.entity.courseware.dietary.DietaryProgramTemplate, co.fitstart.entity.courseware.dietary.DietaryProgramType)
     */
    public void editDiet(BatchCoursewareTemplate batchCoursewareTemplate, DietaryProgramTemplate dietaryProgramTemplate,
            DietaryProgramType dietaryProgramType) {
        genericDaoSupport.update(batchCoursewareTemplate.editDiet(dietaryProgramTemplate, dietaryProgramType));
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#editDiet(co.fitstart.entity.courseware.fitnessgroup.SpecialCoursewareTemplate, co.fitstart.entity.courseware.dietary.DietaryProgramTemplate, co.fitstart.entity.courseware.dietary.DietaryProgramType)
     */
    public void editDiet(SpecialCoursewareTemplate specialCoursewareTemplate,
            DietaryProgramTemplate dietaryProgramTemplate, DietaryProgramType dietaryProgramType) {
        genericDaoSupport.update(specialCoursewareTemplate.editDiet(dietaryProgramTemplate, dietaryProgramType));
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#createSnack(co.fitstart.entity.courseware.dietary.DietaryProgramTemplate, java.lang.Long)
     */
    public void createSnack(DietaryProgramTemplate template, Long dietaryProgramTemplateId) {
        genericDaoSupport.update(template.editSnacks(dietaryProgramTemplateId));
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#loadCoursewareTemplate(java.lang.Long)
     */
    public CoursewareTemplate loadCoursewareTemplate(Long coursewareTemplateId) {
        return genericDaoSupport.load(CoursewareTemplate.class, coursewareTemplateId);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#createCoursewareTemplate(co.fitstart.entity.courseware.fitnessgroup.DailyCoursewareTemplate, co.fitstart.entity.courseware.fitnessgroup.CoursewareTemplate)
     */
    public void createCoursewareTemplate(DailyCoursewareTemplate dailyCoursewareTemplate,
            CoursewareTemplate coursewareTemplate, CoursewareMovementType movementType) {
        
        if(dailyCoursewareTemplate.getType() == null || dailyCoursewareTemplate.getType().isRest()) {
            genericDaoSupport.update(dailyCoursewareTemplate.changeType(DailyCoursewareType.TRAINING));
        }
        
        genericDaoSupport.save(coursewareTemplate.initilization(dailyCoursewareTemplate, movementType));
        
        if(coursewareTemplate.getType() != null) {
            List<CoursewareTemplate> coursewareTemplates = groupTemplateDao.listCoursewareTemplate(dailyCoursewareTemplate, coursewareTemplate.getType());
            
            if(!coursewareTemplates.isEmpty() && coursewareTemplates.get(0).getRanking() != null) {
                genericDaoSupport.update(coursewareTemplate.editRanking(coursewareTemplates.size()));
            }
        }
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#createCoursewareTemplate(co.fitstart.entity.courseware.fitnessgroup.SpecialCoursewareTemplate, co.fitstart.entity.courseware.fitnessgroup.CoursewareTemplate, co.fitstart.entity.courseware.fitnessgroup.CoursewareMovementType)
     */
    public void createCoursewareTemplate(SpecialCoursewareTemplate specialCoursewareTemplate,
            CoursewareTemplate coursewareTemplate) {
        genericDaoSupport.save(coursewareTemplate.initilization(specialCoursewareTemplate));
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#createCoursewareGroup(co.fitstart.entity.courseware.fitnessgroup.DailyCoursewareTemplate, co.fitstart.entity.courseware.fitnessgroup.FitnessGroup, co.fitstart.entity.courseware.fitnessgroup.CoursewareMovementType)
     */
    public void createCoursewareGroup(DailyCoursewareTemplate dailyCoursewareTemplate,
            FitnessGroup fitnessGroup, CoursewareMovementType type) {
        
        if(dailyCoursewareTemplate.getType() == null || dailyCoursewareTemplate.getType().isRest()) {
            genericDaoSupport.update(dailyCoursewareTemplate.changeType(DailyCoursewareType.TRAINING));
        }
            
            // list this group's dailyCourseware template
            SpecialCoursewareTemplate specialCoursewareTemplate = groupTemplateDao.loadSpecialCoursewareTemplate(fitnessGroup);
            if(specialCoursewareTemplate != null) {
                List<CoursewareTemplate> coursewareTemplates = groupTemplateDao.listCoursewareTemplate(specialCoursewareTemplate);
                
                // create courseware template
                for(CoursewareTemplate template : coursewareTemplates) {
                    CoursewareTemplate coursewareTemplate = new CoursewareTemplate(template, dailyCoursewareTemplate, type);
                    genericDaoSupport.save(coursewareTemplate);
                }
                
            }
        
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#editCoursewareTemplate(co.fitstart.entity.courseware.fitnessgroup.CoursewareTemplate)
     */
    public void editCoursewareTemplate(CoursewareTemplate coursewareTemplate) {
        genericDaoSupport.update(coursewareTemplate);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#deleteCoursewareTemplate(co.fitstart.entity.courseware.fitnessgroup.CoursewareTemplate)
     */
    public void deleteCoursewareTemplate(CoursewareTemplate coursewareTemplate) {
        genericDaoSupport.update(coursewareTemplate.disable());
        
        if(coursewareTemplate.getRanking() != null) {
            groupTemplateDao.riseRankingBehind(coursewareTemplate.getDaily(), coursewareTemplate.getType(), coursewareTemplate.getRanking());
        }
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#loadSpecialCoursewareTemplate(co.fitstart.entity.courseware.fitnessgroup.FitnessGroup)
     */
    public SpecialCoursewareTemplate loadSpecialCoursewareTemplate(FitnessGroup fitnessGroup) {
        return groupTemplateDao.loadSpecialCoursewareTemplate(fitnessGroup);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#loadSpecialCoursewareTemplate(java.lang.Long)
     */
    public SpecialCoursewareTemplate loadSpecialCoursewareTemplate(Long specialId) {
        return genericDaoSupport.load(SpecialCoursewareTemplate.class, specialId);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#loadDietaryProgramTemplate(java.lang.Long)
     */
    public DietaryProgramTemplate loadDietaryProgramTemplate(Long templateId) {
        return genericDaoSupport.load(DietaryProgramTemplate.class, templateId);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#editTips(co.fitstart.entity.courseware.fitnessgroup.BatchCoursewareTemplate, java.lang.String)
     */
    public void editTips(BatchCoursewareTemplate batchCoursewareTemplate, String coachTips) {
        genericDaoSupport.update(batchCoursewareTemplate.editTips(coachTips));
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#riseRanking(co.fitstart.entity.courseware.fitnessgroup.CoursewareTemplate)
     */
    public void riseRanking(CoursewareTemplate coursewareTemplate) {
        this.initRanking(coursewareTemplate);
        
        CoursewareTemplate formerCoursewareTemplate = groupTemplateDao.getCoursewareTemplate(coursewareTemplate.getDaily(), coursewareTemplate.getType(), coursewareTemplate.getRanking() - 1);
        
        if(formerCoursewareTemplate != null) {
            genericDaoSupport.update(coursewareTemplate.riseRanking());
            
            genericDaoSupport.update(formerCoursewareTemplate.dropRanking());
        }
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.GroupTemplateService#dropRanking(co.fitstart.entity.courseware.fitnessgroup.CoursewareTemplate)
     */
    public void dropRanking(CoursewareTemplate coursewareTemplate) {
        this.initRanking(coursewareTemplate);
        
        CoursewareTemplate latterCoursewareTemplate = groupTemplateDao.getCoursewareTemplate(coursewareTemplate.getDaily(), coursewareTemplate.getType(), coursewareTemplate.getRanking() + 1);
        
        if(latterCoursewareTemplate != null) {
            genericDaoSupport.update(coursewareTemplate.dropRanking());
            
            genericDaoSupport.update(latterCoursewareTemplate.riseRanking());
        }
    }
    
    /**
     * 
     * @param coursewareTemplate
     */
    private void initRanking(CoursewareTemplate coursewareTemplate) {
        if(coursewareTemplate.getRanking() == null) {
            List<CoursewareTemplate> coursewareTemplates = groupTemplateDao.listCoursewareTemplate(coursewareTemplate.getDaily(), coursewareTemplate.getType());
            int i = 1;
            
            for(CoursewareTemplate eachCoursewareTemplate : coursewareTemplates) {
                genericDaoSupport.update(eachCoursewareTemplate.editRanking(i++));
            }
        }
    }
}
